package srzy.rb

import scala.collection.mutable.ListBuffer

case class DCElement(szElement: String = "", szValue: String = "", iIsParameter: Int = 0)

case class RBMsg(msgData: List[DCElement]) {

  def getValue(pszFieldName: String, iIndex: Int): String = {
    msgData.find(x => x.szElement == pszFieldName && x.iIsParameter == iIndex).map(_.szValue) match {
      case Some(v) => v
      case None => null
    }
  }

  def hasField(field: String): Boolean = {
    msgData.exists(x => x.szElement == field)
  }

  def getMsgData(): Array[DCElement] = msgData.toArray

}

case object RBMsg extends srzy.common.Logging {

  val HEAD_SIZE = 20
  val MAX_MSG_SIZE = 2048

  var msgId = 0

  def getMsgId = {
    msgId += 1
    msgId
  }

  val rbHeaderFields: List[(String, Int)] = List(("MsgId", 8), ("Priority", 1), ("Version", 1),
    ("MsgType", 2), ("ResultCode", 4), ("MsgLength", 4))
  val rbHeaderLength = rbHeaderFields.map(_._2.toInt).reduceLeft(_ + _)
  val rbHeaderFieldsInfo = rbHeaderFields
    .map(x => (x._1, x._2.toInt)).scanLeft(("", (0, 0)))((a, b) => {
      (b._1, (if (a._1 == "") 0 else a._2._1 + a._2._2, b._2))
    }).tail
  val rbHeaderFieldsInfoMap = rbHeaderFieldsInfo.toMap

  //  println("rbHeaderFields : " + rbHeaderFields)
  //  println("rbHeaderLength : " + rbHeaderLength)
  //  println("rbHeaderFieldsInfo : " + rbHeaderFieldsInfo)
  //  println("rbHeaderFieldsInfoMap : " + rbHeaderFieldsInfoMap)

  def pack(msgBody: String): Array[Byte] = {
    val bodyLen = msgBody.length()
    val msgType = getMsgType(msgBody)

    val headBytes = Array.fill(rbHeaderLength)((0).asInstanceOf[Byte])
    val bodyBytes = msgBody.getBytes()

    List(("MsgId", getMsgId), ("Priority", 2), ("MsgType", msgType), ("MsgLength", bodyLen + headBytes.length))
      .map(x => {
        val name = x._1
        val value = x._2
        val e = rbHeaderFieldsInfoMap.apply(name)
        srzy.common.packunpack.packLong(headBytes, e._1, value.toLong, e._2)
      })

    headBytes ++ bodyBytes
  }

  def getMsgBodyLen(msgHead: Array[Byte]): Int = {
    val e = rbHeaderFieldsInfoMap.apply("MsgLength")
    srzy.common.packunpack.unpackInt(msgHead, e._1, e._2)
  }

  def getMsgBody(msgBody: Array[Byte]): String = {
    new String(msgBody)
  }

  def apply(pszMessage: String): RBMsg = {

    val iLen = pszMessage.length()

    if (iLen < HEAD_SIZE || iLen >= MAX_MSG_SIZE) {
      throw new RBMsgParserException("msg length error!")
    }

    if (pszMessage.charAt(0) != '[' || pszMessage.charAt(iLen - 1) != ']') {
      throw new RBMsgParserException("Receive Msg no head or no tail")
    }

    var iMark: Int = 0
    var szElement: String = ""
    var szValue: String = ""
    var iIsParameter: Int = 0
    val msgData: ListBuffer[DCElement] = ListBuffer.empty[DCElement]

    (0 until iLen).toList.map(i => {
      if ((']' == pszMessage.charAt(i)) && (i != iLen - 1)
        && ('[' != pszMessage.charAt(i + 1))) {
        throw new RBMsgParserException("Receive Msg bracket isn't match")
      }

      if (('[' == pszMessage.charAt(i)) && (i != 0)
        && (']' != pszMessage.charAt(i - 1))) {
        throw new RBMsgParserException("Receive Msg bracket isn't match")
      }

      if ('[' == pszMessage.charAt(i) && 0 == iMark) {
        iIsParameter = 0
        iMark = 1
      } else if ('=' == pszMessage.charAt(i) && 1 == iMark) {
        iMark = 2
      } else if (']' == pszMessage.charAt(i) && 2 == iMark) {
        msgData.append(DCElement(szElement, szValue, iIsParameter))
        szElement = ""
        szValue = ""
        iMark = 0
      } else if (';' == pszMessage.charAt(i) && 2 == iMark
        && szElement.substring(0, 3).compareTo("000") != 0) {
        msgData.append(DCElement(szElement, szValue, iIsParameter))
        szElement = ""
        szValue = ""
        // 该项为某组的参数项
        iIsParameter = 2
        iMark = 1
      } else if (',' == pszMessage.charAt(i) && 2 == iMark
        && szElement.substring(0, 3).compareTo("000") != 0) {
        msgData.append(DCElement(szElement, szValue, iIsParameter))
        szElement = ""
        szValue = ""
        // 该项为某组的参数子项
        iIsParameter = 1
        iMark = 1
      } else if (1 == iMark) {
        szElement = szElement + String.valueOf(pszMessage.charAt(i))
      } else if (2 == iMark) {
        szValue = szValue + String.valueOf(pszMessage.charAt(i))
      }
    })
    RBMsg(msgData.toList)
  }

  def dealElement(e: srzy.rb.DCElement, compLog: StringBuffer, b: RBMsg): Boolean = {
    val l = List("R54", "B07", "R69", "210", "001", "R604")
    l.contains(e.szElement)
    if (!l.contains(e.szElement)) {
      compLog append ("Check data is:" + e.szElement + "=" + e.szValue + "\n")
      var result = ""
      if (e.iIsParameter == 0) {
        result = b.getValue(e.szElement, 0)
        if (result == null) {
          return false
        }
        if (e.szValue.compareTo(result) != 0) {
          return false
        }
        true
      } else {
        for (i <- 0 to 10) {
          result = b.getValue(e.szElement, i)
          if (result == null) {
            return false
          }
          if (e.szValue.compareTo(result) != 0) {
            return false
          }
        }
        true
      }
    } else {
      true
    }
  }

  def compare(a: RBMsg, b: RBMsg): (Boolean, String) = {

    val compLog = new StringBuffer
    compLog append "-----------\n"
    val iter = a.getMsgData().iterator
    var flag = true
    while (iter.hasNext && flag == true) {
      val e = iter.next()
      flag = dealElement(e, compLog, b)
    }

    (flag, compLog.toString())
  }

  def compare2(a: String, b: String) = {
    val l = List("101", "000", "001", "100", "B22", "EVT")
    val l2 = List("R604", "R71", "R603", "R615")
    val rList = l2.map(x => (x + "=[^,;=]*").r)

    def getList(s: String) = {
      val rList = l2.map(x => (x + """=[^,;=\[\]]*""").r)
      val s2 = rList.foldLeft(s)((x, r) => {
        r.replaceAllIn(x, "")
      })
      //      println(s2)
      val ll = s2.substring(s2.indexOf("[") + 1, s2.lastIndexOf("]")).split("\\]\\[").toList
      //      println(ll)
      ll.filter(x => {
        val idx = x.indexOf("=")
        if (idx != -1)
          !l.contains(x.substring(0, idx))
        else
          false
      })

    }
    val la = getList(filterBrace(a))
    val lb = getList(filterBrace(b))
    //            println(la)
    //            println(lb)
    val lll = la.zipAll(lb, "", "")
    var complog = ""
    var flag: Boolean = true
    val iter = lll.iterator

    while (iter.hasNext && flag == true) {
      val (sa, sb) = iter.next
      def sort(s: String) = {
        s.split(";").toList.sortWith(_ > _).mkString("\n")
      }
      if (sort(sa).replaceAll("[,]+", " ") != sort(sb).replaceAll("[,]+", " ")) {
        complog = "a:" + sa + "\nb:" + sb
        logger.debug("\na:" + sa + "\nb:" + sb)
        flag = false
      }
    }
    (flag, complog)
  }

}